package de.akabahn.ebd.dbd.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.Observer;

import de.akabahn.ebd.comm.dbd.DBDCommand;
import de.akabahn.ebd.comm.dbd.DBDParameter;

/**
 * Mock extension of the <code>DBDAdapter</code> that doesn't require
 * a DBD connection and still handles all DBD operations.
 *
 * @author moschlar
 * @since 2.1.1
 * @version 2.1.1
 * @see de.akabahn.ebd.dbd.DBDAdapterFactory
 */
public class DBDAdapterMock extends DBDAdapterImpl {

    private final Map<String, Integer> dbd_vars;
    private final Map<String, Integer> dbd_vars_forced;

    /**
     * Initialize the instance with mock key-value stores for variables and
     * forced variables and adding the observer objects
     * to it.
     *
     * @param connectionObservers
     *            The observer classes that want to get notified when the
     *            mocked connection status  changes
     * @see DBDAdapterImpl#DBDAdapterImpl(Observer...)
     */
    public DBDAdapterMock(Observer... connectionObservers) {
        super(connectionObservers);
        this.dbd_vars = new HashMap<String, Integer>();
        this.dbd_vars_forced = new HashMap<String, Integer>();
    }

    /**
     * Pretend to have establish the connection to the DBD server and
     * set the life cycle status of this instance to <code>started</code>.
     */
    @Override
    public synchronized void start() {
        if (!isStarted()) {
            setStarted(true);
        }
    }

    /**
     * Pretend to have disconnected from the DBD server and
     * set the life cycle status of this instance to <code>stopped</code>.
     */
    @Override
    public synchronized void stop() {
        if (isStarted()) {
            setStarted(false);
        }
    }

    /**
     * Write the passed <code>DBDParameter</code> to the mocked key-value stores.
     *
     * @param dbd
     *            The parameter to send
     * @see DBDAdapterImpl#write(DBDParameter)
     */
    @Override
    synchronized void write(final DBDParameter dbd) {
        switch (dbd.getCommand()) {
            case NONE:
                break;
            case ENDOFSESSION:
                break;
            case SUBSCRIBE:
                break;
            case QUERY:
                if (!dbd_vars.containsKey(dbd.getName())) {
                    dbd_vars.put(dbd.getName(), 0);
                }
                onInputAvailable(new DBDParameter(DBDCommand.NONE, dbd.getName(), dbd_vars.get(dbd.getName())));
                break;
            case SET:
                if (!dbd_vars_forced.containsKey(dbd.getName())) {
                    dbd_vars.put(dbd.getName(), dbd.getValue());
                }
                break;
            case FORCE:
                dbd_vars.put(dbd.getName(), dbd.getValue());
                dbd_vars_forced.put(dbd.getName(), dbd.getValue());
                break;
            case UNFORCE:
                dbd_vars_forced.remove(dbd.getName());
                break;
            default:
                throw new AssertionError(dbd.getCommand().name());
        }
    }

    /**
     * Load all known variables from the mocked key-value stores.
     */
    @Override
    void loadDBDVariables() {
        setDBDVariables(dbd_vars.keySet().toArray(new String[dbd_vars.size()]));
    }

}
